package fi.helsinki.cs.kaisei;

/**
 * @author Team TA's
 */

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

import fi.helsinki.cs.kaisei.Weekday.Day;

public class Cli {

        private static Scanner input = new Scanner(System.in); 
        private static Schedule schedule = null;
        private static Timetable timetable = null;
        private static final String endCommand = "/q";
        private static ObjectOutputStream objectOutput;
        private static ObjectInputStream objectInput;
        
        public static void main(String[] args) {
                Character foo;
                do {
                        System.out.println();
                        printCommands();
                        printPrompt();
                        foo = sanitize(input.nextLine());

                        switch (foo) {
                        
                        case 'p':
                                if (schedule == null) { // cannot do this if schedule is not existing
                                        break;
                                }
                                printReportDialogToScreenDialog();
                                break;                                
                        case 'a':
                                if (timetable == null) { // cannot do this if timetable is not existing 
                                        break;
                                }
                                newEventDialog();
                                break;
                        case 't':
	                            if (schedule == null) { // cannot do this if schedule is not existing 
	                                    break;
	                            }
	                            newTimetableDialog();
	                            break;
                        case 's':
                                if (schedule == null) { // cannot do this if schedule is not existing
                                        break;
                                }
                                saveScheduleDialog();
                                break;
                        case 'f':
                                if (schedule == null) { // cannot do this if schedule is not existing
                                        break;
                                }
                                printReportToFileDialog();
                                break;        
                        case 'n':
                                newScheduleDialog();
                                break;
                        case 'o':
                                openScheduleDialog();
                                break;
                        case 'q':
                                System.exit(0);
                                break;

                        default:
                                System.out.println("Don't know what that command is");
                                break;
                        
                        }
                } while (true);
        }

        private static boolean checkDate(String in) {
                Integer day = null;
                // try-catch makes sure that input is numeric 
                try {
                        day = Integer.parseInt(in);
                        // check if day is indeed a valid number
                        if (day > 0 && day < 8) {
                                return true; // day ok, exit!
                        }

                        System.out.println("Sorry, but \""+day+"\" is not a valid number for date");
                } catch (NumberFormatException e) {     
                        System.out.println("Sorry, cannot parse \""+in+"\"");
                }
                
                return false;
        }

        private static void newEventDialog() {
                String startTime = null, endTime = null, location = null, title = null, eventDayTemp;
                Event event = null;
                Day eventDay = null;

                do {
                        System.out.println("");

                        System.out.println("Which day is the event?");
                        printDates();
                        printPrompt();
                        eventDayTemp =  input.nextLine();

                        if (eventDayTemp.equals(endCommand)) {
                                return;
                        }

                        System.out.println("What is the start time?");
                        printPrompt();
                        startTime = input.nextLine();

                        System.out.println("What is the end time?");
                        printPrompt();
                        endTime = input.nextLine();

                        System.out.println("What this event should be named as?");
                        System.out.println("(just press enter to skip this)");
                        printPrompt();
                        title = input.nextLine();

                        System.out.println("Where this event is held?");
                        System.out.println("(just press enter to skip this)");
                        printPrompt();
                        location = input.nextLine();

                        try {
                                if (!checkDate(eventDayTemp)) {
                                        continue;
                                }

                                eventDay = Weekday.intToEnumMap.get(Integer.parseInt(eventDayTemp));
                                event = new Event(startTime, endTime, title, location);
                                break; // success, get out of the do-while
                        } catch (IllegalArgumentException e) {

                                System.out.println("Sorry, but some mistakes were made:");
                                System.out.println(e.getMessage());
                        }
                } while (true);

                System.out.print("Adding event to timetable...");

                try {
                        timetable.addEvent(eventDay, event);
                } catch (IllegalArgumentException e) {
                        System.out.println("Something went wrong:");
                        System.out.println(e.getMessage());
                        System.out.println("Sorry, but once more");
                        newEventDialog();
                        return; // this is for when newEventDialog finally succeeds, we don't print out the last ok!'s
                }
                
                System.out.println("ok!");
        }
        
        private static void newTimetableDialog() {
            String startWeek = null, endWeek = null;

            do {
                    System.out.println("");

                    System.out.println("What week does this timetable start?");
                    printPrompt();
                    startWeek = input.nextLine();

                    System.out.println("What week does this timetable end?");
                    printPrompt();
                    endWeek = input.nextLine();

                    try {
                            timetable = new Timetable(Integer.valueOf(startWeek).intValue(),Integer.valueOf(endWeek).intValue());
                            break; // success, get out of the do-while
                    } catch (IllegalArgumentException e) {
                            System.out.println("Sorry, but some mistakes were made:");
                            System.out.println(e.getMessage());
                    }
            } while (true);

            System.out.print("Adding timetable to schedule...");

            try {
                    schedule.addTimetable(timetable);
            } catch (IllegalArgumentException e) {
                    System.out.println("Something went wrong:");
                    System.out.println(e.getMessage());
                    System.out.println("Sorry, but once more");
                    newEventDialog();
                    return; // this is for when newEventDialog finally succeeds, we don't print out the last ok!'s
            }

            System.out.println("ok!");
    }

        private static void newScheduleDialog() {
                System.out.println("Enter the period this schedule is for:");
                printPrompt();
                String period = input.nextLine();

                System.out.print("Creating schedule...");
                
                schedule = new Schedule(period);

                System.out.println("ok!");
        }

        private static boolean open(String filename) {                
                objectInput = null; // nullify in case something is wrong and it's open
                
                FileInputStream fos = null;
                
                try {
                        fos = new FileInputStream(filename);
                } catch (FileNotFoundException e) {
                        System.out.println("File \"" + filename + "\" couldn't be opened");
                        return false;
                }
                
                try {
                        objectInput = new ObjectInputStream(fos);
                } catch (IOException e) {
                        System.out.println("Cannot read \"" + filename + "\" from FileInputStream");
                        return false;
                }
                
                try {
                        schedule = (Schedule)objectInput.readObject(); // have to cast the object
                        return true;
                } catch (IOException e) {
                        System.out.println("Cannot read \"" + filename + "\" from ObjectInputStream");
                } catch (ClassNotFoundException e) {
                        System.out.println("Cannot find class for the object when reading \"" + filename + "\"");
                }
                
                return false;
        }

        private static void openScheduleDialog() {
                System.out.println("Give name of the file to be opened");
                printPrompt();
                String filename = input.nextLine().trim();
                while (true) {
                        
                        if (!filename.endsWith(".dat")) {
                                filename += ".dat";
                        }
                        
                        if (open(filename)) {
                                break;
                        }
                        else {
                                System.out.println("Please enter the name of the file again");
                                System.out.println("You can exit with " + endCommand);
                                
                                filename = input.nextLine().trim();
                                if (filename.equals(endCommand)){
                                        return;
                                }                              
                        }
                }
        }

        private static void printCommands() {
                System.out.println("Commands");
                System.out.println("--------");
                System.out.println("[N]ew schedule");
                System.out.println("[O]pen schedule from file");
                if (timetable != null)
                	System.out.println("[A]dd event to timetable");
                if (schedule != null) {
                		System.out.println("Add [T]imetable to schedule");
                        System.out.println("[S]ave schedule to file");
                        System.out.println("[P]rint a report on screen");
                        System.out.println("Print a report to [F]ile");
                }
                System.out.println("[Q]uit");
        }

        private static void printDates() {
                System.out.print("Dates are: ");
                for (Day d : Day.values()) {
                        System.out.print(Weekday.enumToIntMap.get(d));
                        System.out.print(" - ");
                        System.out.print(Weekday.longNameMap.get(d));
                        System.out.print(" ");
                }       
                System.out.println();
        }

        private static void printPrompt() {
                System.out.print("?>");
        }

        private static Report printReportDialog() {
            String startWeek = null, endWeek = null;
            ArrayList<Timetable> timetables = null;
            
            do {
                    System.out.println("");

                    System.out.println("Starting from what week do you want to print timetables?");
                    printPrompt();
                    startWeek = input.nextLine();

                    System.out.println("Ending at what week do you want to print timetables?");
                    printPrompt();
                    endWeek = input.nextLine();

                    try {
                            timetables =schedule.searchTimetables(Integer.valueOf(startWeek).intValue(),Integer.valueOf(endWeek).intValue());
                            break; // success, get out of the do-while
                    } catch (IllegalArgumentException e) {

                            System.out.println("Sorry, but some mistakes were made:");
                            System.out.println(e.getMessage());
                    }
            } while (true);

            return new Report(timetables);
        }

        private static void printReportToFileDialog() {
                Report report = printReportDialog();
                if (report != null) {
                        PrintWriter out = null;
                        String filename = null;
                        
                        System.out.println("Give full file name and path (if applicable)");
                        
                        while (true) {
                                printPrompt();
                                try {
                                        filename = input.nextLine().trim();
                                        out = new PrintWriter(filename);
                                        break; // break out of the loop
                                } catch (FileNotFoundException e) {
                                        System.out.println("File " + filename + " was not found");
                                }
                        }
                        
                        System.out.print("Writing the file...");
                        out.print(report);
                        out.close();
                        System.out.println("ok!");
                }
        }

        private static void printReportDialogToScreenDialog() {
                Report report = printReportDialog();
                if (report != null) {
                        System.out.println(report);
                }                
        }

        private static Character sanitize(String rawInput){
                Character input = ' ';  
                if (rawInput != null && rawInput.length()>0)
                        input  = rawInput.toLowerCase().charAt(0);
                return input;
        }

        private static boolean save(String filename) {        
                // nullify static variable to be sure
                objectOutput = null;
                
                FileOutputStream fos = null;
                
                try {
                        fos = new FileOutputStream(filename);   
                } catch (FileNotFoundException e) {
                        System.out.println("Cannot open \"" + filename + "\", something's wrong with it");
                        return false;
                }
                
                try {
                        //output is Cli's static variable
                        objectOutput = new ObjectOutputStream(fos);
                } catch (IOException e) {
                        System.out.println("Cannot write to \"" + filename + "\"");
                        return false;
                }
                
                try {
                        objectOutput.writeObject(schedule);
                        objectOutput.close();
                        return true;
                } catch (IOException e) {
                        System.out.println("Writing to \"" + filename + "\" failed");
                        return false;
                }        
        }

        private static void saveScheduleDialog() {
                System.out.println("Give name of the file to open");
                System.out.println("Notice that file will be saved with .dat-extension, eg. \"myfile\" will be \"myfile.dat\" ");
                printPrompt();
                String filename = input.nextLine().trim() + ".dat";
                while (true) {
                        if (save(filename)) {
                                break;
                        }
                        else {
                                System.out.println("Please enter the name of the file again");
                                System.out.println("You can exit with " + endCommand);
                                filename = input.nextLine().trim();
                                
                                if (filename.trim().toLowerCase().equals(endCommand))
                                        return;
                                else
                                        filename += ".dat";
                        }
                }
                System.out.println("Schedule saved as \"" + filename + "\"");
        }    
}
